package cn.maihe.elg.operation.supports.system;

import cn.maihe.elg.operation.exception.SystemRuntimeException;
import cn.maihe.elg.operation.repository.entity.OperateLogDO;
import cn.maihe.elg.operation.utils.IdGenerate;
import cn.maihe.elg.operation.utils.UserContextUtil;
import cn.maihe.framework.starter.mybatis.dao.MybatisDaoImpl;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @Description
 * @Author WJH
 * @Date 2021/03/26
 */
@Aspect
@Component
@Slf4j
public class OperateLogAspect {

    private final Environment env;

    @Autowired
    public OperateLogAspect(Environment env) {
        this.env = env;
    }

    private String getRealIp(HttpServletRequest request) {
        // 这个一般是Nginx反向代理设置的参数
        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 处理多IP的情况（只取第一个IP）
        if (ip != null && ip.contains(",")) {
            String[] ipArray = ip.split(",");
            ip = ipArray[0];
        }
        return ip;
    }

    /**
     * Controller层create*切点
     */
    @Pointcut("execution (* cn.maihe.elg.operation.web..*.create*(..))")
    public void createPointCut() {
    }

    /**
     * Controller层modify*切点
     */
    @Pointcut("execution (* cn.maihe.elg.operation.web..*.modify*(..))")
    public void modifyPointCut() {
    }

    /**
     * Controller层delete*切点
     */
    @Pointcut("execution (* cn.maihe.elg.operation.web..*.delete*(..))")
    public void deletePointCut() {
    }


    /**
     * 环绕通知 用于拦截Controller层记录用户的操作
     */
    @Around("createPointCut() || modifyPointCut() || deletePointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        OperateLogDO.OperateLogDOBuilder builder = OperateLogDO.builder();
        Object obj = null;
        String operateRemark = "";
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String ip = getRealIp(request);
            String orgCode = UserContextUtil.getUserContext().getOrgCode();
            builder.id(IdGenerate.getId()).orgCode(orgCode).ip(ip)
                    .operateMenu(request.getRequestURI() + ":" + request.getMethod());

            String targetName = proceedingJoinPoint.getTarget().getClass().getName();
            String methodName = proceedingJoinPoint.getSignature().getName();
            Object[] arguments = proceedingJoinPoint.getArgs();
            Class targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();

            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        operateRemark = method.getAnnotation(ApiOperation.class).value();
                        break;
                    }
                }
            }
            obj = proceedingJoinPoint.proceed();
            builder.operateRemark(operateRemark + " :成功");
        } catch (Throwable e) {
            log.error("操作异常信息:{}-{}", operateRemark, e.getMessage());
            builder.operateRemark(StringUtils.truncate(operateRemark + " :失败[" + getExceptionMsg(e) + "]", 300));
            throw e;
        } finally {
            MybatisDaoImpl.run().insertAllColumn(builder.build());
        }
        return obj;
    }

    private String getExceptionMsg(Throwable throwable) {
        if (throwable != null) {
            if (throwable instanceof SystemRuntimeException) {
                SystemRuntimeException e = (SystemRuntimeException) throwable;
                String msg = env.getProperty(e.getCode().name());
                return MessageFormatter.arrayFormat(msg, e.getArgs()).getMessage();
            } else {
                return throwable.getMessage();
            }
        }
        return "";
    }


}
